#include "PackageQueue.h"
#include <algorithm>
#include <wx/log.h>

namespace Impp
{

PackageQueue::PackageQueue() :
	rates(NULL),tasks(NULL)
{
}

PackageQueue::~PackageQueue()
{
}

void PackageQueue::setTaskManager(TaskManager* tasks){
	this->tasks=tasks;
}

void PackageQueue::addToQueue(CliPackage* pack, const Priority & priority, const TaskHandle & handleType, const qword & handle){
	QueuePackage qp;
	qp.pack=pack;
	qp.priority=priority;
	qp.handleType=handleType;
	qp.handle=handle;
	
	if(rates!=NULL){
		qp.rate = rates->getRateByFamilyPair(pack->getData());
	}else{
		qp.rate=NULL;
	}
	
	queue.push_back(qp);
}

QueuePackage PackageQueue::getNextPackageToSend(){

	if(!queue.empty()){
		
		if(rates!=NULL){
			std::sort(queue.begin(),queue.end(),cmp);
			
			std::vector<QueuePackage>::iterator dIter(queue.begin()); 
			
			for (; dIter != queue.end(); ++dIter) { 
				QueuePackage qp = (*dIter);
				
				Rate* rate = qp.rate;

				dword newLevel = rates->calculateNextLevel(rate,false);
				RateState state = rates->getRateState(rate,newLevel);
				
				wxLogTrace(wxT("RATE"),wxT("Level woud be: %i , State would be: %i"), newLevel, state);
				
				if(state==RATE_LIMITED){
					wxLogTrace(wxT("RATE"),wxT("Rate State woud be limited, skip package"));
					
					if(qp.handleType != TASK_HANDLE_NOHANDLE){
						//tasks->getTask();
						wxASSERT(tasks!=NULL);
						
						Task* task = tasks->getTask(qp.handleType,qp.handle);
						if(task!=NULL){
							task->packageHasToWait();
						}
						
					}
					
					
				}else{
					Task* task = tasks->getTask(qp.handleType,qp.handle);
					if(task!=NULL){
						task->packageSent();
					}
					
					QueuePackage ret = (*dIter);
					dIter = queue.erase(dIter);
					return ret;
				}
				
			}
			wxLogTrace(wxT("RATE"),wxT("No Package can be sand without exceed rate Alert limit, queue size is know: %i"),queue.size());
		}else{
			QueuePackage qp = queue.front();
			queue.erase(queue.begin());
			return qp;
		}
	}
	QueuePackage qp;
	qp.pack=NULL;
	qp.rate=NULL;
	return qp;
}

void PackageQueue::deleteQueue(){
	while(!queue.empty()){
		QueuePackage qp = queue.back();
		delete qp.pack;
		queue.pop_back();
	}
	rates=NULL;
}

void PackageQueue::setRateManagement(RateManagement* rates){
	this->rates=rates;
}

const bool PackageQueue::cmp(const QueuePackage & a, const QueuePackage & b){
	return a.priority > b.priority;
}

}
